package client

import (
	"context"
	"encoding/json"
	"fmt"
	_type "gitee.com/freedom_feel/gui-bos-api/common/type"
	"gitee.com/freedom_feel/gui-bos-api/global"
	"gitee.com/freedom_feel/gui-bos-api/logs"
	"time"

	"github.com/redis/go-redis/v9"
)

var rdb *redis.Client

func InitRedis() {
	redisCfg := global.Config.Redis
	//网址: https://gitee.com/qishibo/AnotherRedisDesktopManager 挺好用的
	rdb = redis.NewClient(&redis.Options{
		Addr:     redisCfg.RedisHot + ":" + redisCfg.RedisPort,
		Password: redisCfg.RedisPwd, //不知道为什么 用可视化工具链接需要pwd 代码不需要
		//Addr:     "47.105.127.185" + ":" + "26739",
		//Password: "wangmeng123456", //不知道为什么 用可视化工具链接需要pwd 代码不需要
		DB: 0,
	})
	if _, err := rdb.Ping(context.Background()).Result(); err != nil {
		logs.Error(err.Error())
		_type.ErrChan <- *_type.ErrSystem("redis缓存连接失败")
		return
	}
	logs.Info("redis init success")
	return
}

func RedisSet(key string, value interface{}) error {
	data, _ := json.Marshal(value)
	_, err := rdb.Set(context.Background(), key, data, 30*time.Minute).Result()
	if err != nil {
		return err
	}
	return nil
}

func RedisSetKeepTTL(key string, value interface{}) error {
	data, _ := json.Marshal(value)
	// Lua 脚本：先获取 TTL，再 SET 并恢复 TTL
	script := `
		local ttl = redis.call("TTL", KEYS[1])
		redis.call("SET", KEYS[1], ARGV[1])
		if ttl > 0 then
			redis.call("EXPIRE", KEYS[1], ttl)
		end
		return ttl
	`
	// 执行脚本
	ttl, err := rdb.Eval(context.Background(), script, []string{key}, data).Int()

	//_, err := rdb.Set(context.Background(), key, data, redis.KeepTTL).Result()
	if err != nil {
		return err
	}
	logs.Info(fmt.Sprintf("Updated key with TTL:%v", ttl))
	return nil
}

func RedisSetUserData(key string, value interface{}, keepTime time.Duration) error {
	data, _ := json.Marshal(value)
	_, err := rdb.Set(context.Background(), key, data, keepTime*time.Second).Result()
	if err != nil {
		return err
	}
	return nil
}

func RedisGet(key string) (string, error) {
	res, err := rdb.Get(context.Background(), key).Result()
	if err != nil {
		return "", err
	}
	return res, nil
}

func RedisIncr(key string) {
	_, err := rdb.Incr(context.Background(), key).Result()
	if err != nil {
		fmt.Println(err)
		return
	}
	return
}

func RedisExpireat(key string) error {

	// 获取当前时间
	now := time.Now()

	// 计算今日零点的时间
	midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())

	// 计算明日零点的时间
	nextMidnight := midnight.Add(24 * time.Hour)

	_, err := rdb.ExpireAt(context.Background(), key, nextMidnight).Result()
	if err != nil {
		return err
	}
	return nil
}

func RedisTimeThree(key, value string) error {
	_, err := rdb.Set(context.Background(), key, value, 30*time.Minute).Result()
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

func RdKeepToken(key, value string, keepTime time.Duration) error {
	_, err := rdb.Set(context.Background(), key, value, keepTime*time.Second).Result()
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

func RedisTimeTwo(key, value string) error {
	_, err := rdb.Set(context.Background(), key, value, 20*time.Minute).Result()
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

func RedisExist(key string) bool {
	res := rdb.Exists(context.Background(), key)
	if res.Err() != nil {
		fmt.Println(res.Err())
		return false
	}
	//fmt.Println(res.Val())
	if res.Val() != 1 {
		return false
	}
	return true
}

// 删除 key
func RedisDel(key string) bool {
	res := rdb.Del(context.Background(), key)
	if res.Err() != nil {
		fmt.Println(res.Err())
		return false
	}
	//fmt.Println(res.Val())
	if res.Val() != 1 {
		return false
	}
	return true
}

func GetRedisCode(key string) string {
	result, err := rdb.Get(context.Background(), key).Result()
	if err != nil {
		fmt.Println(err)
		return ""
	}
	return result
}

func RedisCodeTime(key, value string, minute time.Duration) error {
	_, err := rdb.Set(context.Background(), key, value, minute*time.Minute).Result()
	if err != nil {
		return err
	}
	return nil
}

func LPushList(key, value string) error {
	cmd, err := rdb.LPush(context.Background(), key, value).Result()
	if err != nil {
		return err
	}
	fmt.Println(cmd)
	return nil
}

func LGetList(key string) (data string, err error) {
	cmd, err := rdb.LPop(context.Background(), key).Result()
	if err != nil {
		return "", err
	}
	return cmd, nil
}

// AddToZSet 向有序集合添加元素
func AddToZSet(key string, value string, priority float64) error {
	err := rdb.ZAdd(context.Background(), key, redis.Z{Score: priority, Member: value}).Err()
	if err != nil {
		return fmt.Errorf("ZADD failed: %v", err)
	}
	return nil
}

// AddToZSetWithDefaultScore 向有序集合添加元素（使用默认 score）
func AddToZSetWithDefaultScore(key string, value string) error {
	err := rdb.ZAdd(context.Background(), key, redis.Z{Score: global.DefaultScore, Member: value}).Err()
	if err != nil {
		logs.Error(fmt.Sprintf("ZADD failed: %v", err))
		return fmt.Errorf("ZADD failed: %v", err)
	}
	return nil
}

// GetZSetRange 获取有序集合中的元素（按优先级排序）
func GetZSetRange(key string, start, stop int64) ([]string, error) {
	result, err := rdb.ZRange(context.Background(), key, start, stop).Result()
	if err != nil {
		return nil, fmt.Errorf("ZRANGE failed: %v", err)
	}
	return result, nil
}

// GetNextElement 逐个获取有序集合中的元素
func GetNextElement(key string, start int64) (string, int64, error) {
	// 每次获取一个元素
	result, err := rdb.ZRange(context.Background(), key, start, start).Result()
	if err != nil {
		return "", start, fmt.Errorf("ZRANGE failed: %v", err)
	}
	if len(result) == 0 {
		return "", start, fmt.Errorf("no more elements")
	}
	// 返回当前元素和下一个游标
	return result[0], start + 1, nil
}

// RemoveFromZSet 从有序集合中删除元素
func RemoveFromZSet(key string, value string) error {
	err := rdb.ZRem(context.Background(), key, value).Err()
	if err != nil {
		return fmt.Errorf("ZREM failed: %v", err)
	}
	return nil
}
